package us.icitap.cm.business.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;

import org.eclipse.persistence.annotations.Customizer;

import us.icitap.cm.utils.MyCustomizer;

@Entity
@Customizer(MyCustomizer.class)
@Table(name="REPORT", schema="MPC")
@TableGenerator(name="REPORT_IDS",table="AUTO_IDS",valueColumnName="LAST_ID",initialValue=1, allocationSize=1,schema="MPC")
public class Report implements Serializable{

	
	public enum RestrictionEnum{
		PUBLIC,
		PRIVATE,
		RESTRICTED;
		
	}
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 5407915902174437535L;
	
	@Id
	@GeneratedValue(strategy=GenerationType.TABLE,generator="REPORT_IDS")
	private Integer id;
	
	@ManyToOne
	@JoinColumn(name="CASE_ID")
	private Case policeCase;
	
	@OneToOne(mappedBy="report")
	private EventReport eventReport;
	
	
	
	@OneToOne(mappedBy="report")
	private SupplementReport supplementReport;
	
	@Enumerated(EnumType.STRING)
	@Column(name="REPORT_TYPE", length=2)
	private ReportTypeEnum reportType;
	
	@ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinTable(name="MPC.REPORT_ENTITY", joinColumns=@JoinColumn(name="REPORT_ID"), inverseJoinColumns=@JoinColumn(name="APP_ENTITY_ID"))
	private List<AppEntity> entityList;
	
	@Transient
	private List<Evidence> evidenceList;
	
//	@OneToMany(mappedBy="report", cascade=CascadeType.ALL)
//	private List<EntityReportAssociation> entityReportAssocList;

	@OneToMany(mappedBy="report",cascade=CascadeType.ALL)
	private List<EntityEntityAssociation> entityEntityAssocList;
	
	@ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinTable(name="MPC.REPORT_POLICE_CODE", joinColumns=@JoinColumn(name="REPORT_ID"), inverseJoinColumns=@JoinColumn(name="POLICE_CODE"))
	private List<PoliceCode> policeCodeList;
	
	
	
	@ManyToOne
	@JoinColumn(name="PRIM_POLICE_CODE_ID")
	private PoliceCode primaryPoliceCode;
	
	@OneToMany(mappedBy="report")
	private List<Control> controlList;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="REPORT_DATE")
	private Date reportDate;
	
	@Column(name="RECORD_USER",length=60)
	private String recordUser;
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="RECORD_DATE")
	private Date recordDate;
	
	
	@ManyToOne
	@JoinColumn(name="REPORT_OFFICER_ID")
	private Officer reportOfficer;
	
	
	@ManyToOne
	@JoinColumn(name="INVEST_STARTED_METH_ID")
	private AppList investStartedMethod;
	
	@Column(name="INVEST_STARTED_DESC", length=200)
	private String investStartedDescription;
	
	@ManyToOne
	@JoinColumn(name="ORG_STRUCTURE_ID")
	private OrgStructure orgStructure;
	
	@ManyToOne
	@JoinColumn(name="INVEST_METHOD_ID")
	private AppList investigationMethod;
	
	@Column(name="INVEST_METH_DESC", length=200)
	private String investMethodDescription;
	
	@OneToOne(mappedBy="report")
	@JoinColumn
	private PoliceOperation policeOperation;
	
	@Enumerated(EnumType.STRING)
	@Column(name="RESTRICTION")
	private RestrictionEnum resitriction;
	
	private List<ReportRestriction> reportRestrictionList;
	
	
	@Lob
	@Column(name="NOTES")
	private String notes;
	
 	
	@Transient
	public String tempUniqueNumber;

	public Report() {
		super();
	}
	
	
	
	public Report(String recordUser) {
		super();
		this.recordUser = recordUser;
	}
	
	public AppEntity getAppEntity(AppEntity appEntity){
		for (AppEntity ae : this.getEntityList()) {
			if(ae.myEquals(appEntity)) return ae;
		}
		return null;
	}
	
	public void addAppEntity(AppEntity appEntity){
		if(this.entityList == null) this.entityList = new ArrayList<AppEntity>();
		this.entityList.add(appEntity);
	}
	public void addAppEntityList(List<AppEntity> appEntityList){
		if(appEntityList == null) return;
		if(this.entityList == null) this.entityList = new ArrayList<AppEntity>();
		this.entityList.addAll(appEntityList);
	}
	public void addReportAppEntityList(List<AppEntity> appEntityList){
		if(appEntityList == null) return;
		if(this.entityList == null) this.entityList = new ArrayList<AppEntity>();
		
		for (AppEntity appEntity : appEntityList) {
			if(appEntity.getEntityType().equals(EntityTypeEnum.PLACE)
				|| appEntity.getEntityType().equals(EntityTypeEnum.PERSON)
				|| appEntity.getEntityType().equals(EntityTypeEnum.DOCUMENT)
				|| appEntity.getEntityType().equals(EntityTypeEnum.VEHICLE)
				|| appEntity.getEntityType().equals(EntityTypeEnum.ITEM)
				|| appEntity.getEntityType().equals(EntityTypeEnum.DRUG)
				|| appEntity.getEntityType().equals(EntityTypeEnum.WEAPON)
				|| appEntity.getEntityType().equals(EntityTypeEnum.ORGANIZATION)
				|| appEntity.getEntityType().equals(EntityTypeEnum.OFFICER)){
				
				this.entityList.add(appEntity);
				
			}
		}
		
	}
	
	public boolean removeAppEntity(AppEntity appEntity){
//		this.removeEntityReportAssocList(appEntity);
		return this.getEntityList().remove(appEntity);
		
	}
	
//	public void removeEntityReportAssocList(AppEntity appEntity){
//		if(this.getEntityReportAssocList() != null && !this.getEntityReportAssocList().isEmpty()){
//			 for(Iterator<EntityReportAssociation> itr = getEntityReportAssocList().iterator();itr.hasNext();){
//				 EntityReportAssociation era = itr.next();
//				 if(era.getAppEntity().equals(appEntity)){
//					 itr.remove();
//
//				 }
//					 
//			 }
//		}
//	}
	
//	public boolean hasEntityReportAssication(AppEntity appEntity){
//		if(this.getEntityReportAssocList() != null && !this.getEntityReportAssocList().isEmpty()){
//			for(EntityReportAssociation era: this.getEntityReportAssocList()){
//				if(era.getAppEntity().equals(appEntity)) return true;
//			}
//			return false;
//		}
//		return false;
//	}
	
//	public void addEntityReportAssociation(EntityReportAssociation entityReportAssociation){
//		if(this.entityReportAssocList == null) this.entityReportAssocList = new ArrayList<EntityReportAssociation>();
//		entityReportAssociation.setReport(this);
//		this.entityReportAssocList.add(entityReportAssociation);
//	}
//	
//	public void addEntityReportAssociationList(List<EntityReportAssociation> entityReportAssociationList){
//		if(entityReportAssociationList == null) return;
//		if(this.entityReportAssocList == null) this.entityReportAssocList = new ArrayList<EntityReportAssociation>();
//		for (EntityReportAssociation era : entityReportAssociationList) {
//			era.setReport(this);
//			if(!this.entityReportAssocList.contains(era)){
//				this.entityReportAssocList.add(era);
//			}
//			
//		}
//		
//	}

	public void addEntityEntityAssociation(EntityEntityAssociation entityEntityAssociation){
		if(this.entityEntityAssocList == null) this.entityEntityAssocList = new ArrayList<EntityEntityAssociation>();
		
		this.entityEntityAssocList.add(entityEntityAssociation);
		
	}
	
	public void addEntityEntityAssociationList(List<EntityEntityAssociation> entityEntityAssociationList){
		if(entityEntityAssociationList == null) return;
		if(this.entityEntityAssocList == null) this.entityEntityAssocList = new ArrayList<EntityEntityAssociation>();
		this.entityEntityAssocList.addAll(entityEntityAssociationList);
	}
	
	public void addControl(Control control){
		if(controlList == null) this.controlList = new ArrayList<Control>();
		this.controlList.add(control);
	}
	
	public List<AppEntity> getAppEntityByType(EntityTypeEnum entityTypeEnum){
		List<AppEntity> tempList = new ArrayList<AppEntity>();
		if(this.getEntityList() == null) return null;
		for (AppEntity e : this.getEntityList()) {

				if(e.getEntityType().equals(entityTypeEnum)) tempList.add(e);
		}
		return tempList;
	}
	
	public List<EntityEntityAssociation> getEntityAssocAsOneList(AppEntity appEntity){
		
		if(this.entityEntityAssocList == null) return null;
		List<EntityEntityAssociation> list = new  ArrayList<EntityEntityAssociation>();
		for (EntityEntityAssociation eea : this.getEntityEntityAssocList()) {
			if(eea.getEntityOne().equals(appEntity)) list.add(eea);
			else if(eea.getEntityTwo().equals(appEntity)) list.add(eea);
		}
		return list;
	}
	
//	public List<EntityReportAssociation> getEntityReportAssocList(AppEntity appEntity){
//		if(this.entityReportAssocList == null) return null;
//		List<EntityReportAssociation> list = new  ArrayList<EntityReportAssociation>();
//		for (EntityReportAssociation era : this.entityReportAssocList) {
//			if(era.getAppEntity().equals(appEntity)) list.add(era);
//		}
//		return list;
//	}
	
	@Transient
	public void setAppEntitiesAsNotNewRecords(){
		if(this.entityList == null) return;
		for (AppEntity appEntity : this.entityList) {
			appEntity.setNewRecord(false);
		}
	}
	@Override
	public String toString() {
		if(ReportTypeEnum.ER.equals(this.reportType)) return this.getEventReport().toString();
		if(ReportTypeEnum.SR.equals(this.reportType)) return this.getSupplementReport().toString();
		return null;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Case getPoliceCase() {
		return policeCase;
	}

	public void setPoliceCase(Case policeCase) {
		this.policeCase = policeCase;
	}

	public EventReport getEventReport() {
		return eventReport;
	}

	public void setEventReport(EventReport eventReport) {
		this.eventReport = eventReport;
	}

	public SupplementReport getSupplementReport() {
		return supplementReport;
	}

	public void setSupplementReport(SupplementReport supplementReport) {
		this.supplementReport = supplementReport;
	}

	public ReportTypeEnum getReportType() {
		return reportType;
	}

	public void setReportType(ReportTypeEnum reportType) {
		this.reportType = reportType;
	}

	public List<AppEntity> getEntityList() {
		return entityList;
	}

	public void setEntityList(List<AppEntity> entityList) {
		this.entityList = entityList;
	}

//	public List<EntityReportAssociation> getEntityReportAssocList() {
//		return entityReportAssocList;
//	}
//
//	public void setEntityReportAssocList(
//			List<EntityReportAssociation> entityReportAssocList) {
//		this.entityReportAssocList = entityReportAssocList;
//	}
	
	
	public List<EntityEntityAssociation> getEntityEntityAssocList() {
		return entityEntityAssocList;
	}
	public void setEntityEntityAssocList(
			List<EntityEntityAssociation> entityEntityAssocList) {
		this.entityEntityAssocList = entityEntityAssocList;
	}
	public List<PoliceCode> getPoliceCodeList() {
		return policeCodeList;
	}
	public void setPoliceCodeList(List<PoliceCode> policeCodeList) {
		this.policeCodeList = policeCodeList;
	}
	public Date getReportDate() {
		return reportDate;
	}
	public void setReportDate(Date reportDate) {
		this.reportDate = reportDate;
	}
	public String getRecordUser() {
		return recordUser;
	}
	public void setRecordUser(String recordUser) {
		this.recordUser = recordUser;
	}
	public Date getRecordDate() {
		return recordDate;
	}
	public void setRecordDate(Date recordDate) {
		if(this.entityList != null){
			for (AppEntity appEntity : this.entityList) {
				if(appEntity.getRecordDate() == null)
					appEntity.setRecordDate(recordDate);
			}
		}
		this.recordDate = recordDate;
	}
	public AppList getInvestStartedMethod() {
		return investStartedMethod;
	}
	public void setInvestStartedMethod(
			AppList investStartedMethod) {
		this.investStartedMethod = investStartedMethod;
	}
	public String getInvestStartedDescription() {
		return investStartedDescription;
	}
	public void setInvestStartedDescription(String investStartedDescription) {
		this.investStartedDescription = investStartedDescription;
	}
	public OrgStructure getOrgStructure() {
		return orgStructure;
	}
	public void setOrgStructure(OrgStructure orgStructure) {
		this.orgStructure = orgStructure;
	}
	public AppList getInvestigationMethod() {
		return investigationMethod;
	}
	public void setInvestigationMethod(AppList investigationMethod) {
		this.investigationMethod = investigationMethod;
	}
	public String getInvestMethodDescription() {
		return investMethodDescription;
	}
	public void setInvestMethodDescription(String investMethodDescription) {
		this.investMethodDescription = investMethodDescription;
	}
	public PoliceOperation getPoliceOperation() {
		return policeOperation;
	}
	public void setPoliceOperation(PoliceOperation policeOperation) {
		this.policeOperation = policeOperation;
	}
	
	
	public PoliceCode getPrimaryPoliceCode() {
		return primaryPoliceCode;
	}

	public void setPrimaryPoliceCode(PoliceCode primaryPoliceCode) {
		this.primaryPoliceCode = primaryPoliceCode;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Report other = (Report) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

	public Officer getReportOfficer() {
		return reportOfficer;
	}

	public void setReportOfficer(Officer reportOfficer) {
		this.reportOfficer = reportOfficer;
	}

	public String getTempUniqueNumber() {
		return tempUniqueNumber;
	}

	public void setTempUniqueNumber(String tempUniqueNumber) {
		this.tempUniqueNumber = tempUniqueNumber;
	}



	public List<Evidence> getEvidenceList() {
		return evidenceList;
	}



	public void setEvidenceList(List<Evidence> evidenceList) {
		this.evidenceList = evidenceList;
	}



	public List<Control> getControlList() {
		return controlList;
	}



	public void setControlList(List<Control> controlList) {
		this.controlList = controlList;
	}



	public RestrictionEnum getResitriction() {
		return resitriction;
	}



	public void setResitriction(RestrictionEnum resitriction) {
		this.resitriction = resitriction;
	}



	public List<ReportRestriction> getReportRestrictionList() {
		return reportRestrictionList;
	}



	public void setReportRestrictionList(
			List<ReportRestriction> reportRestrictionList) {
		this.reportRestrictionList = reportRestrictionList;
	}



	public String getNotes() {
		return notes;
	}



	public void setNotes(String notes) {
		this.notes = notes;
	}



	
}
